﻿using System;
using System.Runtime.InteropServices;

namespace ImageProcessing.Service
{
    /// <summary>
    /// 图像处理库的互操作类。
    /// 提供对图像处理 DLL 的动态调用封装。
    /// </summary>
    public class CvLibInterop : IDisposable
    {
        private nint _dllHandle;

        // 委托声明
        public delegate nint InitImageDrHanderDelegate(string modelPath, int someInt);

        public delegate void CloseImageDrHandlerDelegate(nint handler);

        public delegate double SkewAngleDelegate(nint handler, string imagePath);

        public delegate nint DeskewingDelegate(nint handler, string inputImagePath, string outputImagePath);

        public delegate int TextImageOrientationDelegate(nint handler, string imagePath);

        public delegate void RotateDelegate(nint handler, string imagePath, int angle, string outputImagePath);

        public delegate nint CleanupDelegate(nint handler, string inputname, string outputname);

        public delegate nint RemoveBlackEdgesDelegate(string inputname, string outputname, double thresholdValue);

        public delegate nint SetToWhiteDelegate(string inputname, string outputname, int x, int y, int width, int height, int inside);

        public delegate nint ChangeGammaDelegate(string inputname, string outputname, double gammaValue);

        public delegate nint ChangeContrastAndBrightDelegate(string inputname, string outputname, double contrast, double brightValue);

        public delegate nint DeskewingWithAngleDelegate(nint handler, string inputname, double angle, string outputname);

        /// <summary>
        /// * 初始化图像处理引擎
        //* gpu_id = -1 使用CPU资源
        //* gpu_id = 0...，使用GPU卡，根据要使用系统的GPU卡数量设置
        /// </summary>
        public InitImageDrHanderDelegate initImageDrHander;

        /// <summary>
        /// 释放图像处理引擎占用资源
        /// </summary>
        public CloseImageDrHandlerDelegate closeImageDrHandler;

        /// <summary>
        ///图像倾斜角度检测
        ///文本图像的小角度倾斜检测，本功能只支持<45°的角度检测，返回值为正数时，为顺时针倾斜，为负数时为逆时针倾斜。
        /// </summary>
        public SkewAngleDelegate skewAngle;

        /// <summary>
        /// 图像自动倾斜角度检测并纠斜
        /// </summary>

        public DeskewingDelegate deskewing;

        /// <summary>
        /// 文本图像的方向 0,90,180,270
        /// </summary>
        public TextImageOrientationDelegate textImageOrientation;

        /// <summary>
        /// 图像大方向旋转： 0,90,180,270
        /// </summary>
        public RotateDelegate rotate;

        /// <summary>
        /// 图像清洁
        /// 图像清洁功能，为自动根据图像的特征，去除图像的背景色、污渍等。
        /// 图像清洁功能模型、数据运算量较大，运行时间较长CPU环境约6秒，GPU环境约2秒。建议在GPU环境下，人工手动运行。
        /// </summary>
        public CleanupDelegate cleanup;

        /// <summary>
        /// * 去除图像的黑边
        ///
        ///* thresholdValue: 根据图像调整黑色阈值
        /// </summary>
        public RemoveBlackEdgesDelegate removeBlackEdges;

        /// <summary>
        /// * 将指定矩形区域内或区域外的颜色设置为白色
        ///* x, y: 指定区域的左上角坐标
        ///* width，height： 指定区域的宽，高
        ///* inside = 0 设置区域外，inside=1设置区域内
        /// </summary>
        public SetToWhiteDelegate setToWhite;

        /// <summary>
        /// 调整图像文字颜色
        /// gammaValue的取值范围1.0 -- 20.0
        ///调整的步进可取0.5
        /// </summary>
        public ChangeGammaDelegate changeGamma;

        public ChangeContrastAndBrightDelegate changeContrastAndBright;
        public DeskewingWithAngleDelegate deskewingWithAngle;

        /// <summary>
        /// 初始化 CvLibInterop 类的新实例，并加载指定的 DLL。
        /// </summary>
        /// <param name="dllPath">DLL 文件的路径。</param>
        public CvLibInterop(string dllPath)
        {
            try
            {
                SetDllDirectory(Path.GetDirectoryName(dllPath));
                _dllHandle = LoadLibraryEx(dllPath, nint.Zero, LoadLibraryFlags.LOAD_WITH_ALTERED_SEARCH_PATH);
                if (_dllHandle == nint.Zero)
                {
                    int errorCode = Marshal.GetLastWin32Error();
                    throw new Exception($"Failed to load DLL: {dllPath}. Error code: {errorCode}");
                }

                // 加载原有函数
                initImageDrHander = GetDelegate<InitImageDrHanderDelegate>("initImageDrHander", CallingConvention.Cdecl);
                closeImageDrHandler = GetDelegate<CloseImageDrHandlerDelegate>("closeImageDrHandler", CallingConvention.Cdecl);
                skewAngle = GetDelegate<SkewAngleDelegate>("skewAngle", CallingConvention.Cdecl);
                deskewing = GetDelegate<DeskewingDelegate>("deskewing", CallingConvention.Cdecl);
                textImageOrientation = GetDelegate<TextImageOrientationDelegate>("textImageOrientation", CallingConvention.Cdecl);
                rotate = GetDelegate<RotateDelegate>("rotate", CallingConvention.Cdecl);
                //cleanup = GetDelegate<CleanupDelegate>("cleanup", CallingConvention.Cdecl);
                removeBlackEdges = GetDelegate<RemoveBlackEdgesDelegate>("removeBlackDdges", CallingConvention.Cdecl);
                setToWhite = GetDelegate<SetToWhiteDelegate>("setToWhite", CallingConvention.Cdecl);
                changeGamma = GetDelegate<ChangeGammaDelegate>("changeGamma", CallingConvention.Cdecl);
                changeContrastAndBright = GetDelegate<ChangeContrastAndBrightDelegate>("changeContrastAngBright", CallingConvention.Cdecl);
                deskewingWithAngle = GetDelegate<DeskewingWithAngleDelegate>("deskewingWithAngle", CallingConvention.Cdecl);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        /// <summary>
        /// 释放由 CvLibInterop 占用的所有资源。
        /// </summary>
        public void Dispose()
        {
            if (_dllHandle != nint.Zero)
            {
                FreeLibrary(_dllHandle);
                _dllHandle = nint.Zero;
            }
        }

        private T GetDelegate<T>(string functionName, CallingConvention callingConvention) where T : Delegate
        {
            nint procAddress = GetProcAddress(_dllHandle, functionName);
            if (procAddress == nint.Zero)
            {
                throw new Exception($"Failed to get address for function: {functionName}");
            }
            return (T)Marshal.GetDelegateForFunctionPointer(procAddress, typeof(T));
        }

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        private static extern nint LoadLibraryEx(string dllToLoad, nint hFile, LoadLibraryFlags dwFlags);

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool FreeLibrary(nint hModule);

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern nint GetProcAddress(nint hModule, string procedureName);

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        private static extern bool SetDllDirectory(string lpPathName);

        [Flags]
        private enum LoadLibraryFlags : uint
        {
            DONT_RESOLVE_DLL_REFERENCES = 0x00000001,
            LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010,
            LOAD_LIBRARY_AS_DATAFILE = 0x00000002,
            LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040,
            LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020,
            LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200,
            LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000,
            LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100,
            LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800,
            LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400,
            LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008
        }
    }
}